<script setup lang="ts">
import { ref, onMounted, onUnmounted, shallowRef } from "vue"
import * as echarts from "echarts"

// 图表引用
const chartRef = shallowRef<HTMLElement | null>(null)
const chartInstance = shallowRef<echarts.ECharts | null>(null)
let animationTime = 0
let animationFrameId: number | null = null

// 模拟数据
const chartData = ref([
    { name: "视频课程", processed: 60, unprocessed: 40, total: 100 },
    { name: "互动测验", processed: 25, unprocessed: 15, total: 40 },
    { name: "实践任务", processed: 30, unprocessed: 30, total: 60 },
    { name: "阅读资料", processed: 45, unprocessed: 15, total: 60 },
    { name: "期末考试", processed: 10, unprocessed: 90, total: 100 },
])

// 生命周期钩子
onMounted(() => {
    initWaveChart()
    window.addEventListener("resize", handleResize)
})

onUnmounted(() => {
    // 销毁图表实例
    if (chartInstance.value) {
        chartInstance.value.dispose()
    }

    // 停止动画
    if (animationFrameId !== null) {
        cancelAnimationFrame(animationFrameId)
    }

    window.removeEventListener("resize", handleResize)
})

// 处理窗口大小变化
const handleResize = () => {
    if (chartInstance.value) {
        chartInstance.value.resize()
    }
}

// 初始化水波柱状图
const initWaveChart = () => {
    if (!chartRef.value) return

    // 初始化echarts实例
    chartInstance.value = echarts.init(chartRef.value)

    // 设置图表配置
    updateChartOption()

    // 启动动画
    animate()
}

// 动画函数
const animate = () => {
    animationTime += 0.1
    if (chartInstance.value) {
        chartInstance.value.setOption({
            series: createWaveSeries(),
        })
    }
    animationFrameId = requestAnimationFrame(animate)
}

// 创建水波路径
const createWavePath = (rect: any, waterLevel: number, time: number) => {
    const { x, y, width, height } = rect
    const waterHeight = height * waterLevel
    const waterY = y + height - waterHeight

    const waveLength = width
    const waveHeight = 6
    const frequency = 1

    let path = `M ${x} ${y + height}`
    path += ` L ${x} ${waterY}`

    for (let i = 0; i < width; i += 2) {
        const waveX = x + i + 2
        const waveY = waterY + Math.sin((i / waveLength) * Math.PI * frequency + time) * waveHeight
        path += ` L ${waveX} ${waveY}`
    }

    path += ` L ${x + width} ${y + height}`
    path += ` Z`

    return path
}

// 创建水波系列配置
const createWaveSeries = () => {
    return [
        {
            name: "水波柱状图",
            type: "custom",
            renderItem: (params: any, api: any) => {
                const categoryIndex = api.value(0)
                const totalValue = api.value(1)
                const processedValue = chartData.value[categoryIndex].processed

                const start = api.coord([api.value(0), 0])
                const end = api.coord([api.value(0), totalValue])
                const height = end[1] - start[1]
                const width = 60

                const rectShape = {
                    x: start[0] - width / 2,
                    y: start[1],
                    width: width,
                    height: height,
                }

                const waterLevel = processedValue / totalValue
                const wavePath = createWavePath(rectShape, waterLevel, animationTime)
                return {
                    type: "group",
                    children: [
                        {
                            type: "rect",
                            shape: rectShape,
                            style: {
                                fill: {
                                    type: "linear",
                                    x: 0,
                                    y: 0,
                                    x2: 0,
                                    y2: 1,
                                    colorStops: [
                                        { offset: 0, color: "rgba(24, 144, 255, 0.8)" },
                                        { offset: 0.5, color: "rgba(64, 169, 255, 0.5)" },
                                        { offset: 1, color: "rgba(9, 109, 217, 0.4)" },
                                    ],
                                },
                                stroke: "rgba(24, 144, 255, 0.3)",
                                lineWidth: 1,
                            },
                        },
                        {
                            type: "path",
                            shape: {
                                pathData: wavePath,
                            },
                            style: {
                                fill: {
                                    type: "linear",
                                    x: 0,
                                    y: 0,
                                    x2: 0,
                                    y2: 1,
                                    colorStops: [
                                        { offset: 0, color: "rgba(24, 144, 255, 0.8)" },
                                        { offset: 0.5, color: "rgba(64, 169, 255, 0.6)" },
                                        { offset: 1, color: "rgba(9, 109, 217, 0.4)" },
                                    ],
                                },
                            },
                            z: 10,
                        },
                    ],
                }
            },
            data: chartData.value.map((item) => item.total),
            z: 10,
        },
    ]
}

// 更新图表配置
const updateChartOption = () => {
    if (!chartInstance.value) return

    const option = createOption()
    chartInstance.value.setOption(option)
}

// 创建图表配置
const createOption = () => {
    return {
        backgroundColor: "transparent",
        animation: false,
        tooltip: {
            trigger: "axis",
            axisPointer: { type: "shadow" },
            formatter: function (params: any) {
                const data = chartData.value[params[0].dataIndex]
                return `${data.name}<br/>已完成: ${data.processed}<br/>未完成: ${data.unprocessed}<br/>总计: ${data.total}`
            },
        },
        grid: {
            left: "3%",
            right: "4%",
            bottom: "12%",
            top: "5%",
            containLabel: true,
        },
        xAxis: {
            type: "category",
            data: chartData.value.map((item) => item.name),
            axisLabel: { color: "#555" },
            axisLine: { lineStyle: { color: "#ddd" } },
        },
        yAxis: {
            type: "value",
            axisLabel: { color: "#555", fontSize: 12 },
            axisLine: { lineStyle: { color: "#ddd" } },
            splitLine: { lineStyle: { color: "rgba(220, 220, 220, 0.3)" } },
        },
        series: createWaveSeries(),
    }
}
</script>

<template>
    <div class="wave-chart-demo">
        <h2>水波动效柱状图</h2>

        <div class="intro">
            <p>
                本示例展示了使用echarts的自定义系列（custom
                series）和renderItem方法实现的水波动效柱状图。此效果通过动态生成路径（path）实现，可用于直观展示完成进度、数据占比等情况。
            </p>
        </div>

        <div class="chart-section">
            <h3>示例：学习进度统计</h3>
            <div class="chart-container">
                <div
                    ref="chartRef"
                    class="echarts-container"
                ></div>
            </div>
            <div class="chart-legend">
                <div class="legend-item">
                    <span class="legend-color legend-completed"></span>
                    <span class="legend-text">已完成</span>
                </div>
                <div class="legend-item">
                    <span class="legend-color legend-uncompleted"></span>
                    <span class="legend-text">未完成</span>
                </div>
            </div>
        </div>

        <div class="implementation-details">
            <h3>实现细节</h3>
            <div class="code-details">
                <h4>核心实现</h4>
                <ul>
                    <li>使用echarts的custom系列类型</li>
                    <li>通过renderItem自定义渲染逻辑</li>
                    <li>使用正弦函数Math.sin()计算波浪效果</li>
                    <li>通过requestAnimationFrame持续更新波浪动画</li>
                </ul>
            </div>

            <div class="advantages">
                <h4>优势</h4>
                <ul>
                    <li>更具视觉吸引力的数据展示方式</li>
                    <li>直观展示进度或占比</li>
                    <li>通过动画效果增强用户体验</li>
                    <li>完全自定义的外观和行为</li>
                </ul>
            </div>
        </div>
    </div>
</template>

<style lang="less" scoped>
.wave-chart-demo {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
    font-family: Arial, sans-serif;

    h2 {
        color: #333;
        margin-bottom: 20px;
        text-align: center;
    }

    h3 {
        color: #444;
        margin: 20px 0 15px;
        border-left: 4px solid #1890ff;
        padding-left: 10px;
    }

    h4 {
        color: #555;
        margin: 15px 0 10px;
    }

    .intro {
        background-color: #f8f9fa;
        padding: 15px;
        border-radius: 8px;
        margin-bottom: 20px;
        border-left: 4px solid #1890ff;

        p {
            margin: 0;
            line-height: 1.6;
            color: #555;
        }
    }

    .chart-section {
        margin: 30px 0;
        padding: 20px;
        background-color: #fff;
        border-radius: 8px;
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
    }

    .chart-container {
        position: relative;
        height: 400px;
        margin: 20px 0;

        .echarts-container {
            width: 100%;
            height: 100%;
        }
    }

    .chart-legend {
        display: flex;
        justify-content: center;
        margin-top: 15px;

        .legend-item {
            display: flex;
            align-items: center;
            margin: 0 15px;

            .legend-color {
                display: inline-block;
                width: 16px;
                height: 16px;
                margin-right: 6px;
                border-radius: 3px;
            }

            .legend-completed {
                background: linear-gradient(to bottom, rgba(24, 144, 255, 0.8), rgba(9, 109, 217, 0.4));
            }

            .legend-uncompleted {
                background-color: #f0f0f0;
                border: 1px solid #ddd;
            }

            .legend-text {
                font-size: 14px;
                color: #666;
            }
        }
    }

    .implementation-details {
        display: flex;
        flex-wrap: wrap;
        margin: 20px 0;
        gap: 20px;

        .code-details,
        .advantages {
            flex: 1;
            min-width: 300px;
            padding: 15px;
            background-color: #f8f9fa;
            border-radius: 8px;
        }

        .code-details {
            border-left: 4px solid #722ed1;
        }

        .advantages {
            border-left: 4px solid #52c41a;
        }
    }

    ul {
        padding-left: 20px;

        li {
            margin-bottom: 8px;
            color: #555;
        }
    }

    @media (max-width: 768px) {
        .implementation-details {
            flex-direction: column;
        }

        .chart-container {
            height: 300px;
        }
    }
}
</style>
